import { Component, computed, createApp, h, Ref, ref } from "vue";
import { CallContentStatus } from "@/types/call";
import { getDevices, servers } from "@/utils/call";
import { useUser } from "@/store/modules/user";
import VideoCop from "@/pages/VideoCall/components/Video.vue";
import AudioCop from "@/pages/VoiceCall/components/Audio.vue";

interface ICallStreamMap {
  mediaStream: MediaStream;
  peerConnection: RTCPeerConnection | null;
}

interface ICandidateInfo {
  id: number;
  avatar: string;
  name: string;
}

// 明确区分组件和渲染函数类型
export function useWebRtc(type: "video" | "audio" = "audio", containerRef: Ref, recordTimeFunc: Function) {
  const user = useUser();
  let activeVideoDeviceId = ref("");
  let activeAudioDeviceId = ref("");
  let audioDeviceList = ref<MediaDeviceInfo[]>([]);
  let videoDeviceList = ref<MediaDeviceInfo[]>([]);
  let mediaStreamMap = ref(new Map<number, ICallStreamMap>());
  let pendingCandidates = ref<RTCIceCandidate[]>([]);
  let isConnected = ref(false);

  // 获取用户所有设备
  async function GetAllDevices() {
    try {
      audioDeviceList.value = await getDevices("audioinput");
      videoDeviceList.value = await getDevices("videoinput");
      activeAudioDeviceId.value = audioDeviceList.value[0].deviceId;
      activeVideoDeviceId.value = videoDeviceList.value[videoDeviceList.value.length - 1].deviceId;
    } catch (error) {
      console.error("获取用户设备失败");
    }
  }

  // 构建视频组件
  function BuildVideoComponent(info: ICandidateInfo, dynamicComponent: Component) {
    const { id, name, avatar } = info;
    const app = createApp({
      setup() {
        const srcObj = computed(() => mediaStreamMap.value.get(id)?.mediaStream ?? new MediaStream());
        const props = { srcObj: srcObj.value, info: { name, avatar } };
        return () => h(dynamicComponent, props);
      },
    });

    const div = document.createElement("div");
    div.className = "w-full h-full relative";
    app.mount(div);
    containerRef.value?.appendChild(div);
  }

  // 构建音频组件
  function BuildAudioComponent(userId: number, dynamicComponent: Component) {
    const app = createApp({
      setup() {
        const srcObj = computed(() => mediaStreamMap.value.get(userId)?.mediaStream ?? new MediaStream());
        const props = { srcObj: srcObj.value };
        return () => h(dynamicComponent, props);
      },
    });
    const div = document.createElement("div");
    app.mount(div);
    containerRef.value?.appendChild(div);
  }

  //加载本地媒体流
  async function LoadLocalStream(): Promise<MediaStream> {
    let constraints: MediaStreamConstraints = {
      audio: {
        deviceId: activeAudioDeviceId.value,
        echoCancellation: true,
        noiseSuppression: true,
        autoGainControl: true,
      },
    };
    if (type === "video") {
      Object.assign(constraints, {
        video: {
          deviceId: activeVideoDeviceId.value,
        },
      });
    }
    return await window.navigator.mediaDevices.getUserMedia(constraints);
  }

  //切换媒体流
  async function ChangeMediaDevice(type: "audio" | "video", deviceId: string) {
    const local = mediaStreamMap.value.get(user.userId!);
    if (!local) return;

    // 获取新轨道
    const newStream = await navigator.mediaDevices.getUserMedia({ [type]: { deviceId } });
    const newTrack = newStream.getTracks()[0];

    // 替换本地流中的轨道
    const oldTrack = local.mediaStream.getTracks().find((t) => t.kind === type)!;
    local.mediaStream.removeTrack(oldTrack);
    local.mediaStream.addTrack(newTrack);

    // 更新所有 PeerConnection 的发送端
    mediaStreamMap.value.forEach((item, id) => {
      if (id === user.userId || !item.peerConnection) return;
      const sender = item.peerConnection.getSenders().find((s) => s.track?.kind === type);
      if (sender) sender.replaceTrack(newTrack); // 替换发送端的轨道
    });
    // 停止旧的轨道
    oldTrack.stop();
    // 更新设备 ID
    type === "video" ? (activeVideoDeviceId.value = deviceId) : (activeAudioDeviceId.value = deviceId);
  }

  //创建 PeerConnection 并设置回调函数
  async function CreeperConnection(candidateInfo: ICandidateInfo) {
    const existing = mediaStreamMap.value.get(candidateInfo.id);
    if (existing?.peerConnection) return existing.peerConnection;
    const local = mediaStreamMap.value.get(user.userId!);
    if (!local) return null;

    const pc = new RTCPeerConnection(servers);
    const remoteStream = new MediaStream();
    local.peerConnection = pc;
    mediaStreamMap.value.set(candidateInfo.id, { mediaStream: remoteStream, peerConnection: pc });
    // 添加本地轨道
    local.mediaStream.getTracks().forEach((track) => pc.addTrack(track, local.mediaStream));
    // 构建对方的视频或音频组件
    type === "video" ? BuildVideoComponent(candidateInfo, VideoCop) : BuildAudioComponent(candidateInfo.id, AudioCop);
    recordTimeFunc();
    pc.ontrack = (event) => {
      event.streams[0]
        .getTracks()
        .forEach((track) => mediaStreamMap.value.get(candidateInfo.id)?.mediaStream.addTrack(track));
    };
    // 创建offer或者answer时候触发 =》我们先存起来 等交换完的时候发送
    pc.onicecandidate = (event) => {
      if (event.candidate) {
        pendingCandidates.value = [...pendingCandidates.value, event.candidate];
      }
    };

    // 监听连接状态
    pc.oniceconnectionstatechange = () => {
      if (pc.iceConnectionState === "connected") {
        console.log("连接成功");
        isConnected.value = true;
      } else if (pc.iceConnectionState === "failed") {
        console.error("连接失败");
      }
    };

    return pc;
  }

  //创建 Offer 并设置本地描述
  async function CreateOffer(candidateInfo: ICandidateInfo, CreateOfferCallBack: Function): Promise<void> {
    let peerConnection = await CreeperConnection(candidateInfo);
    if (!peerConnection) return;
    let offer = await peerConnection.createOffer();
    await peerConnection.setLocalDescription(offer);
    // 发送offer
    console.log("发送offer");
    CreateOfferCallBack(candidateInfo.id, offer);
  }

  //创建 Answer 并设置本地描述
  async function CreateAnswer(
    candidateInfo: ICandidateInfo,
    offer: RTCSessionDescriptionInit,
    CreateAnswerCallback: Function,
  ): Promise<void> {
    let peerConnection = await CreeperConnection(candidateInfo);
    if (!peerConnection) return;
    await peerConnection.setRemoteDescription(offer);
    let answer = await peerConnection.createAnswer();
    await peerConnection.setLocalDescription(answer);
    console.log("准备发送answer", answer);
    CreateAnswerCallback(candidateInfo.id, answer);
  }

  //添加 Answer 描述
  async function AddAnswer(candidateId: number, answer: RTCSessionDescriptionInit, SendCandidateCallback: Function) {
    const local = mediaStreamMap.value.get(user.userId!);
    if (!local?.peerConnection) return;
    try {
      await local.peerConnection.setRemoteDescription(answer);
      // 发送自己的candidate
      SendCandidateCallback(candidateId, pendingCandidates.value, CallContentStatus.SendCandidate);
    } catch (error) {
      console.error("设置远端描述失败:", error, user.userId);
    }
  }

  // 发送自己的candidate
  function SendCandidate(candidateId: number, candidateList: RTCIceCandidateInit[], SendCandidateCallback: Function) {
    // 处理对方传送过来的candidate
    HandelCandidate(candidateList);
    // 把自己的candidate发送
    SendCandidateCallback(candidateId, pendingCandidates.value, CallContentStatus.ReceiverCandidate);
  }

  // 处理candidate
  function HandelCandidate(candidateList: RTCIceCandidateInit[]) {
    const local = mediaStreamMap.value.get(user.userId!);
    if (!local?.peerConnection) {
      console.warn("PeerConnection 不存在，无法添加候选者", user.userId);
      return;
    }
    candidateList.forEach((candidate) => {
      local.peerConnection!.addIceCandidate(candidate).catch((error) => {
        console.error("添加 candidate 失败:", error, candidate);
      });
    });
  }

  //切换媒体流的状态（启用/禁用）
  function ToggleLocalStream(type: "video" | "audio") {
    let local = mediaStreamMap.value.get(user.userId!);
    if (!local) return;
    let localTrack = local.mediaStream.getTracks().find((track) => track.kind === type);
    if (!localTrack) return;
    localTrack.enabled = !localTrack.enabled;
  }

  return {
    isConnected,
    activeVideoDeviceId,
    activeAudioDeviceId,
    audioDeviceList,
    videoDeviceList,
    mediaStreamMap,
    GetAllDevices,
    BuildVideoComponent,
    LoadLocalStream,
    CreateOffer,
    CreateAnswer,
    SendCandidate,
    AddAnswer,
    HandelCandidate,
    ToggleLocalStream,
    ChangeMediaDevice,
    BuildAudioComponent,
  };
}
